package com.tyk.bookstore.front.order.service.impl;


import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.tyk.bookstore.front.cart.model.dto.Cart4OrderDto;
import com.tyk.bookstore.front.cart.service.ShoppingCartApiService;
import com.tyk.bookstore.front.common.core.model.exception.CustomException;
import com.tyk.bookstore.front.common.core.model.result.CommonResultEnum;
import com.tyk.bookstore.front.common.core.model.vo.PageVo;
import com.tyk.bookstore.front.common.core.util.AssertUtil;
import com.tyk.bookstore.front.common.core.util.IdGenerator;
import com.tyk.bookstore.front.common.core.util.ObjUtil;
import com.tyk.bookstore.front.common.dal.mapper.dto.BinDto;
import com.tyk.bookstore.front.common.dal.mapper.dto.SinDto;
import com.tyk.bookstore.front.common.mq.RabbitManager;
import com.tyk.bookstore.front.member.model.dto.Address4OrderDto;
import com.tyk.bookstore.front.member.service.DeliveryAddressApiService;
import com.tyk.bookstore.front.order.dto.Order4StockDto;
import com.tyk.bookstore.front.order.manager.OrderRedisManager;
import com.tyk.bookstore.front.order.model.dto.OrderBriefDto;
import com.tyk.bookstore.front.order.model.dto.OrderDetailDto;
import com.tyk.bookstore.front.order.model.dto.OrderExplicitDto;
import com.tyk.bookstore.front.order.model.dto.OrderSubmitDto;
import com.tyk.bookstore.front.order.model.emume.OrderState;
import com.tyk.bookstore.front.order.model.entity.OrderDetailDo;
import com.tyk.bookstore.front.order.model.entity.OrderDo;
import com.tyk.bookstore.front.order.model.entity.OrderExtraDo;
import com.tyk.bookstore.front.order.model.query.OrderAddressUpdateQuery;
import com.tyk.bookstore.front.order.model.query.OrderCancelQuery;
import com.tyk.bookstore.front.order.model.query.OrderPageQuery;
import com.tyk.bookstore.front.order.model.query.OrderSubmitQuery;
import com.tyk.bookstore.front.order.model.result.OrderResultEnum;
import com.tyk.bookstore.front.order.model.vo.*;
import com.tyk.bookstore.front.order.mq.MqConstant;
import com.tyk.bookstore.front.order.repository.OrderDetailRepository;
import com.tyk.bookstore.front.order.repository.OrderExtraRepository;
import com.tyk.bookstore.front.order.repository.OrderRepository;
import com.tyk.bookstore.front.order.service.OrderService;
import com.tyk.bookstore.front.order.strategy.split.OrderSplitManager;
import com.tyk.bookstore.front.order.strategy.split.model.SplitDto;
import com.tyk.bookstore.front.order.strategy.split.model.SplitStock;
import com.tyk.bookstore.front.order.util.MapStructOrder;
import com.tyk.bookstore.front.order.util.OrderUtil;
import com.tyk.bookstore.front.order.vo.OrderAddressVo;
import com.tyk.bookstore.front.order.vo.OrderSplitSubDto;
import com.tyk.bookstore.front.order.vo.OrderSplitVo;
import com.tyk.bookstore.front.product.model.dto.Book4OrderDto;
import com.tyk.bookstore.front.product.model.query.Book4OrderPriceCheckQuery;
import com.tyk.bookstore.front.product.service.BookApiService;
import com.tyk.bookstore.front.storage.model.query.Stock4OrderRollBackQuery;
import com.tyk.bookstore.front.storage.service.StockApiService;
import com.tyk.bookstore.front.storage.service.WarehouseApiService;
import com.tyk.bookstore.front.system.model.dto.AreaFullLevelDto;
import com.tyk.bookstore.front.system.service.AreaApiService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author tyk
 * @description 订单管理
 */
@Service
@RequiredArgsConstructor
public class OrderServiceImp implements OrderService {

    private final OrderRepository orderRepository;
    private final OrderDetailRepository orderDetailRepository;
    private final OrderExtraRepository orderExtraRepository;
    private final DeliveryAddressApiService deliveryAddressApiService;
    private final ShoppingCartApiService shoppingCartApiService;
    private final BookApiService bookApiService;
    private final StockApiService stockApiService;
    private final OrderSplitManager orderSplitManager;
    private final OrderRedisManager orderRedisManager;
    private final WarehouseApiService warehouseApiService;
    private final AreaApiService areaApiService;
    private final RabbitManager rabbitManager;
    private final TransactionTemplate transactionTemplate;
    private final MapStructOrder mapStructOrder;

    @Override
    public OrderCreateVo createOrder() {
        Long memberId = StpUtil.getLoginIdAsLong();

        // 获取选中的商品
        List<Cart4OrderDto> cartDtoList = shoppingCartApiService.getCart4OrderDtoListCheckedByMemberId(memberId);
        AssertUtil.isTrue(
                ObjUtil.notEmpty(cartDtoList),
                OrderResultEnum.NO_PRODUCT_SELECTED
        );
        Set<Long> bookIdSet = cartDtoList.stream().map(Cart4OrderDto::getBookId).collect(Collectors.toSet());

        // 获取商品信息
        Map<Long, Book4OrderDto> dtoMap = bookApiService
                .getBook4OrderDtoListByIdSet(bookIdSet)
                .stream().collect(Collectors.toMap(Book4OrderDto::getId, it -> it));

        // 创建订单详情
        String tradeNo = OrderUtil.tradeNo(memberId);
        List<OrderCreateVo.OrderDetailVo> detailVoList = cartDtoList.stream().map(
                cart -> mapStructOrder.toOrderSubmitVo$OrderDetailVo(cart, dtoMap.get(cart.getBookId()))
        ).toList();
        OrderCreateVo orderCreateVo = new OrderCreateVo(tradeNo, detailVoList);

        // 缓存
        orderRedisManager.cacheOrderCreateVo(memberId, orderCreateVo);

        // 返回订单详情
        return orderCreateVo;
    }

    @Override
    public OrderSubmitVo submitOrder(OrderSubmitQuery query) {

        Long memberId = StpUtil.getLoginIdAsLong();

        // 断言地址存在
        deliveryAddressApiService.assertExistById(query.getAddressId(), memberId);

        // 获取缓存的订单创建对象
        OrderCreateVo orderCreateVo = orderRedisManager.getOrderCreateVo(memberId);
        AssertUtil.notNull(orderCreateVo, OrderResultEnum.ORDER_HAS_COMMITTED);

        // 流水号
        query.setTradeNo(orderCreateVo.getTradeNo());

        // 订单明细
        List<OrderCreateVo.OrderDetailVo> detailList = orderCreateVo.getDetailList();
        Map<Long, OrderCreateVo.OrderDetailVo> detailMap = detailList.stream().collect(Collectors.toMap(
                OrderCreateVo.OrderDetailVo::getBookId, it -> it
        ));
        Set<Long> bookIdSet = detailList.stream().map(
                OrderCreateVo.OrderDetailVo::getBookId
        ).collect(Collectors.toSet());

        // 校验书籍是否存在
        bookApiService.assertExistByIdSet(bookIdSet);

        // 校验书籍价格是否变化
        List<Book4OrderPriceCheckQuery> priceCheckQueryList = mapStructOrder.toBook4OrderPriceCheckQuery(detailList);
        bookApiService.assertPriceNotChange(priceCheckQueryList);

        // 父订单
        OrderDo parentOrder = new OrderDo()
                .setId(IdGenerator.id())
                .setOrderNo(OrderUtil.orderNo())
                .setMemberId(memberId)
                .setNote(query.getNote())
                .setState(OrderState.WAIT_PAY);

        // 事务包裹修改操作
        return transactionTemplate.execute(status -> {

            // 缓存订单
            List<OrderDo> allOrderList = new ArrayList<>();

            // 缓存订单明细
            List<OrderDetailDo> allDetailList = new ArrayList<>();


            // 查询收件人地址信息
            Address4OrderDto addressDto = deliveryAddressApiService.getAddress4OrderDtoById(query.getAddressId(), memberId);

            // 拆单
            List<SplitStock> splitStockList = mapStructOrder.toSplitParamList(detailList);
            List<SplitDto> osdList = orderSplitManager.splitThenDeduct(query.getAddressId(), splitStockList);

            // 子订单数量为1时不创建子订单
            if (osdList.size() == 1) {
                parentOrder.setWarehouseId(osdList.get(0).getWarehouseId());
            }

            // 父订单订单明细
            List<OrderDetailDo> parentDetailList = mapStructOrder.toOrderDetailDoList(detailList);
            BigDecimal parentTotalPrice = BigDecimal.valueOf(0L);
            long parentTotalWeight = 0;
            for (OrderDetailDo detailDo : parentDetailList) {
                parentTotalPrice = parentTotalPrice.add(detailDo.getPrice().multiply(BigDecimal.valueOf(detailDo.getNum())));
                parentTotalWeight += detailDo.getWeight() * detailDo.getNum();
            }
            parentOrder.setAmount(parentTotalPrice).setWeight(parentTotalWeight);

            // 缓存父订单
            allOrderList.add(parentOrder);

            // 缓存父订单订单明细
            parentDetailList.forEach(it -> {
                it.setId(IdGenerator.id()).setOrderId(parentOrder.getId()).setMemberId(memberId);
            });
            allDetailList.addAll(parentDetailList);

            // 下单时间
            LocalDateTime createTime = LocalDateTime.now();
            parentOrder.setCreateTime(createTime);

            // 订单提交返回数据
            OrderSubmitVo orderSubmitVo = new OrderSubmitVo(
                    parentOrder.getId(),
                    parentOrder.getOrderNo(),
                    parentOrder.getAmount(),
                    createTime.plusSeconds(OrderRedisManager.getOrderCreateVoExpireTime())
            );

            // 仅含一个子订单时无需创建子订单
            if (osdList.size() > 1) {

                // 创建子订单
                osdList.forEach(osd -> {

                    // 复制父订单共同属性
                    OrderDo order = mapStructOrder.toOrderDo(parentOrder);
                    order.setId(IdGenerator.id());

                    // 子订单属性
                    order.setParentId(parentOrder.getId());
                    order.setOrderNo(OrderUtil.orderNo());
                    order.setWarehouseId(osd.getWarehouseId());


                    // 子订单明细
                    List<OrderDetailDo> subDetailList = osd.getStockList().stream().map(
                            book -> mapStructOrder.toOrderDetailDo(detailMap.get(book.getBookId()))
                    ).toList();

                    // 子订单金额和重量
                    BigDecimal totalPrice = BigDecimal.valueOf(0L);
                    long totalWeight = 0;
                    for (OrderDetailDo detail : subDetailList) {
                        totalPrice = totalPrice.add(detail.getPrice().multiply(BigDecimal.valueOf(detail.getNum())));
                        totalWeight += detail.getWeight() * detail.getNum();
                    }
                    order.setAmount(totalPrice).setWeight(totalWeight);

                    // 缓存子订单
                    allOrderList.add(order);

                    // 缓存子订单订单明细
                    subDetailList.forEach(it -> {
                        it.setId(IdGenerator.id()).setOrderId(order.getId()).setMemberId(memberId);
                    });
                    allDetailList.addAll(subDetailList);

                });
            }

            // 订单添加到数据库
            orderRepository.insertBatch(allOrderList);

            // 订单明细添加到数据库
            orderDetailRepository.insertBatch(allDetailList);

            // 订单额外信息添加到数据库
            List<OrderExtraDo> orderExtraList = allOrderList.stream().map(
                    it -> mapStructOrder.toOrderExtraDo(addressDto).setOrderId(it.getId())
            ).toList();
            orderExtraRepository.insertBatch(orderExtraList);

            // 删除购物车数据
            shoppingCartApiService.deleteByBookIdList(bookIdSet, memberId);

            // 删除缓存的订单创建对象
            orderRedisManager.deleteOrderCreateVo(memberId);

            // 延时队列取消订单
            // Mq监听线程无Web上下文环境，需手动传递memberId
            rabbitManager.sendDelayMsg(
                    MqConstant.ORDER_CANCEL_EXCHANGE,
                    MqConstant.ORDER_CANCEL_ROUTING,
                    parentOrder.getId(),
                    parentOrder.getOrderNo(),
                    Duration.between(LocalDateTime.now(), orderSubmitVo.getDeadline()).getSeconds(),
                    Map.of(MqConstant.ARGS_MEMBER_ID, String.valueOf(memberId))
            );

            return orderSubmitVo;
        });
    }

    @Override
    public void cancel(OrderCancelQuery query) {
        Long memberId = StpUtil.getLoginIdAsLong();
        this.cancel(query, memberId);
    }

    @Override
    public void cancel(OrderCancelQuery query, Long memberId) {

        Long orderId = query.getOrderId();

        // 检查订单是否存在
        AssertUtil.isTrue(
                orderRepository.exist2Eq(
                        OrderDo::getId, orderId,
                        OrderDo::getMemberId, memberId,
                        OrderDo.class
                ),
                OrderResultEnum.ORDER_NOT_FOUND
        );


        // 校验订单是否可以取消
        BinDto<BigInteger, Integer> od = orderRepository.selectBin1Eq(
                OrderDo::getParentId, OrderDo::getState,
                OrderDo::getId, orderId,
                OrderDo.class
        );
        // 订单存在
        AssertUtil.notNull(od, OrderResultEnum.ORDER_NOT_FOUND);
        // 状态为待支付
        AssertUtil.equal(od.getV2(), OrderState.WAIT_PAY.value(), OrderResultEnum.STATE_NOT_SUPPORT_CANCEL);
        // 订单为父订单
        AssertUtil.equal(od.getV1().longValue(), 0L, CommonResultEnum.OPERATION_NOT_SUPPORTED);


        // 查询当前订单的子订单
        Set<Long> subIdSet = orderRepository.<Long>selectSinList1Eq(
                OrderDo::getId, OrderDo::getParentId, orderId, OrderDo.class
        ).stream().map(SinDto::getV1).collect(Collectors.toSet());

        // 事务包裹数据库操作
        transactionTemplate.executeWithoutResult(status -> {
            // 待回滚的库存记录
            List<Stock4OrderRollBackQuery> rbqList = new ArrayList<>();

            // 统计需要回滚的库存
            if (ObjUtil.notEmpty(subIdSet)) {
                // 子订单=>子订单明细
                // key：仓库ID
                Map<Long, List<Order4StockDto>> subOrder2Detail = orderRepository
                        .selectOrder4StockDtoLitByIdSet(subIdSet)
                        .stream().collect(Collectors.groupingBy(
                                Order4StockDto::getWarehouseId
                        ));
                // 库存记录
                subOrder2Detail.forEach((k, v) -> rbqList.add(
                                new Stock4OrderRollBackQuery(
                                        k, mapStructOrder.toStock4OrderRollBackQuery$StockRollBackList(v)
                                )
                        )
                );
                // 删除子订单明细
                orderDetailRepository.delete1In1Eq(
                        OrderDetailDo::getOrderId, subIdSet,
                        OrderDetailDo::getMemberId, memberId,
                        OrderDetailDo.class
                );
                // 删除子订单额外信息
                orderExtraRepository.delete1In(
                        OrderExtraDo::getOrderId, subIdSet,
                        OrderExtraDo.class
                );
                // 删除子订单
                orderRepository.delete1In1Eq(
                        OrderDo::getId, subIdSet,
                        OrderDo::getMemberId, memberId,
                        OrderDo.class
                );
            } else {
                // 仓库ID
                Long warehouseId = orderRepository.<BigInteger>selectSin1Eq(
                        OrderDo::getWarehouseId, OrderDo::getId, orderId, OrderDo.class
                ).getV1().longValue();
                // 订单明细中各书籍数量
                List<Stock4OrderRollBackQuery.Stock> stockList = mapStructOrder.toStock4OrderRollBackQuery$StockRollBack(
                        orderDetailRepository.selectOrderDetail4StockDtoListByOrderId(orderId)
                );
                // 库存记录
                rbqList.add(new Stock4OrderRollBackQuery(warehouseId, stockList));
            }

            // 回滚库存
            stockApiService.rollBack(rbqList);

            // 标记订单为已取消
            // 未删除已取消订单的明细 !!!
            orderRepository.update1Set1Eq(
                    OrderDo::getState, OrderState.CANCEL,
                    OrderDo::getId, orderId,
                    OrderDo.class
            );
            // 记录订单取消时间
            LambdaUpdateWrapper<OrderExtraDo> wrapper = Wrappers.lambdaUpdate();
            wrapper.set(OrderExtraDo::getCancelReason, query.getReason())
                    .set(OrderExtraDo::getCancelTime, LocalDateTime.now())
                    .eq(OrderExtraDo::getOrderId, orderId);
            orderExtraRepository.update(wrapper);
        });

    }

    @Override
    public OrderVo getById(Long id) {

        long memberId = StpUtil.getLoginIdAsLong();

        // 订单核心信息
        OrderDo order = orderRepository.selectById(id);
        AssertUtil.notNull(order, OrderResultEnum.ORDER_NOT_FOUND);
        AssertUtil.equal(memberId, order.getMemberId(), OrderResultEnum.ORDER_NOT_FOUND);
        // 拆单详情不走此接口
        AssertUtil.isFalse(order.getState() == OrderState.SPLIT, CommonResultEnum.OPERATION_NOT_SUPPORTED);

        // 订单额外信息
        OrderExtraDo orderExtra = orderExtraRepository.selectById(id);

        // 订单Vo
        OrderVo ov = mapStructOrder.toOrderVo(order, orderExtra);

        // 收件区域全称
        ov.setCneeAreaFullName(
                areaApiService.getAreaFullNameByCode(ov.getCneeAreaCode())
        );

        // 待支付、已取消订单无仓库ID
        if (ov.getState() != OrderState.WAIT_PAY &&
                ov.getState() != OrderState.CANCEL) {
            // 仓库名称
            ov.setWarehouseName(
                    warehouseApiService.getWarehouseNameById(ov.getWarehouseId())
            );
        }

        // 订单明细
        List<OrderDetailDo> odList = orderDetailRepository.selectListByOrderId(order.getId());
        ov.setDetailList(mapStructOrder.toOrderVo$OrderDetailVo(odList));

        return ov;
    }

    @Override
    public OrderSplitVo getSplitById(Long id) {

        long memberId = StpUtil.getLoginIdAsLong();

        // 存在ID为id且状态为已拆单的订单
        LambdaQueryWrapper<OrderDo> w = Wrappers.lambdaQuery(OrderDo.class);
        w.select(OrderDo::getOrderNo, OrderDo::getCreateTime, OrderDo::getAmount)
                .eq(OrderDo::getId, id)
                .eq(OrderDo::getMemberId, memberId)
                .eq(OrderDo::getState, OrderState.SPLIT);
        OrderDo order = orderRepository.selectOne(w);
        AssertUtil.notNull(order, OrderResultEnum.ORDER_NOT_FOUND);

        // 订单额外信息
        OrderExtraDo orderExtra = orderExtraRepository.selectById(id);

        // 父订单信息
        OrderSplitVo osv = mapStructOrder.toOrderSplitVo(order, orderExtra);

        // 区域名称
        String areaFullName = areaApiService.getAreaFullNameByCode(orderExtra.getCneeAreaCode());
        osv.setCneeAreaFullName(areaFullName);

        // 子订单信息
        List<OrderSplitSubDto> subList = orderRepository.selectSplitOrderSubDtoListByParentId(id);
        osv.setChildren(
                mapStructOrder.toOrderSplitVo$OrderList(subList)
        );

        return osv;
    }

    @Override
    public OrderPageVo getPage(OrderPageQuery query) {

        Long memberId = StpUtil.getLoginIdAsLong();

        // 符合条件的订单的简略信息
        LambdaQueryWrapper<OrderDo> w = buildPageQueryWrapper(query);
        Map<Long, List<OrderBriefDto>> briefMap = orderRepository
                .selectOrderBriefDtoListByCondition(w)
                .stream().collect(Collectors.groupingBy(OrderBriefDto::getParentId));

        // 特判
        if (ObjUtil.isEmpty(briefMap)) {
            return PageVo.instance(OrderPageVo.class);
        }

        // 父级ID集合
        Set<Long> pidSet = new HashSet<>(briefMap.keySet());

        // 去除顶级父ID
        if (briefMap.containsKey(0L)) {
            List<Long> list = briefMap.get(0L).stream().map(OrderBriefDto::getId).toList();
            list.forEach(pidSet::remove);
        }

        // 补充未查询到的父级订单简略信息
        List<OrderBriefDto> parentBriefList = orderRepository.selectOrderBriefDtoListByIdSet(pidSet);

        // 所有父订单的简略信息
        if (briefMap.containsKey(0L))
            parentBriefList.addAll(briefMap.get(0L));

        // 分页参数
        int total = parentBriefList.size();
        int fromIndex = (int) ((query.getPage() - 1) * query.getLimit());
        if (fromIndex >= total) {
            fromIndex = 0;
            query.setPage(1L);
        }
        int toIndex = (int) Math.min(fromIndex + query.getLimit(), total);


        // 按下单时间从新往旧排序
        parentBriefList.sort(Comparator.comparing(OrderBriefDto::getCreateTime, Comparator.reverseOrder()));

        // 截取所需页的数据
        List<OrderBriefDto> parentBriefSubList = parentBriefList.subList(fromIndex, toIndex);

        // 收集需要查询订单详情的订单ID
        Set<Long> needSelectIdSet = new HashSet<>();
        parentBriefSubList.forEach(order -> {
            Long id = order.getId();
            needSelectIdSet.add(id);
            if (briefMap.containsKey(id)) {
                needSelectIdSet.addAll(briefMap.get(id).stream().map(OrderBriefDto::getId).toList());
            }
        });

        // 订单核心信息 key：parentId  value：订单核心信息列表
        List<OrderExplicitDto> explicitList = orderRepository.selectOrderExplicitDtoListByIdSet(needSelectIdSet);
        Map<Long, List<OrderExplicitDto>> egMap = explicitList
                .stream().collect(
                        Collectors.groupingBy(OrderExplicitDto::getParentId)
                );

        // 订单核心信息 key orderId value：订单核心信息
        Map<Long, OrderExplicitDto> ocMap = egMap.get(0L).stream().collect(
                Collectors.toMap(OrderExplicitDto::getId, it -> it)
        );

        // 订单额外信息 key orderId value：订单额外信息
        Map<Long, OrderExplicitDto> oeMap = orderExtraRepository
                .selectOrderExplicitDtoListByIdSet(needSelectIdSet)
                .stream().collect(
                        Collectors.toMap(OrderExplicitDto::getId, it -> it)
                );

        // 可评论的订单ID
        Set<Long> caSet = orderDetailRepository.selectCommentAbleOrderIdByOrderIdSet(needSelectIdSet, memberId);

        // 订单明细
        Map<Long, List<OrderDetailDto>> odMap = orderDetailRepository
                .selectOrderDetailDtoByOrderIdSet(needSelectIdSet, memberId)
                .stream().collect(Collectors.groupingBy(OrderDetailDto::getOrderId));

        // 特判：防止存在父订单无子订单的情况
        if (ObjUtil.isEmpty(odMap)) {
            return PageVo.instance(OrderPageVo.class);
        }


        // 转换
        // egMap.get(0L) 等价于 parentBriefSubList
        // parentBriefSubList 经过排序
        List<OrderPageVo.Order> records = parentBriefSubList.stream().map(it -> {
            OrderPageVo.Order pov = mapStructOrder.toOrderPageVo$Order(
                    ocMap.get(it.getId()), oeMap.get(it.getId())
            );
            if (pov.getState() == OrderState.SPLIT) {
                List<OrderPageVo.Order> subList = egMap.get(pov.getId()).stream().map(sub -> {
                    OrderPageVo.Order spv = mapStructOrder.toOrderPageVo$Order(sub, oeMap.get(sub.getId()));
                    spv.setDetailList(
                            mapStructOrder.toOrderPageVo$OrderDetailList(odMap.get(sub.getId()))
                    ).setCommentAble(caSet.contains(sub.getId()));
                    return spv;
                }).toList();
                pov.setChildList(subList);
            } else {
                pov.setDetailList(
                        mapStructOrder.toOrderPageVo$OrderDetailList(odMap.get(pov.getId()))
                ).setCommentAble(caSet.contains(pov.getId()));
            }
            return pov;
        }).toList();

        // 返回
        OrderPageVo orderPageVo = new OrderPageVo();
        orderPageVo.setCurrent(query.getPage()).setSize(query.getLimit()).setRecords(records).setTotal((long) total);

        return orderPageVo;
    }


    @Override
    public OrderSubmitVo getWaitPayInfo(Long orderId) {

        Long memberId = StpUtil.getLoginIdAsLong();

        // 检查订单是否存在
        AssertUtil.isTrue(
                orderRepository.exist2Eq(
                        OrderDo::getId, orderId,
                        OrderDo::getMemberId, memberId,
                        OrderDo.class
                ),
                OrderResultEnum.ORDER_NOT_FOUND
        );

        // 查询待支付订单数据
        OrderSubmitDto submitDto = orderRepository.selectOrderSubmitDto(orderId, memberId);
        AssertUtil.notNull(submitDto, OrderResultEnum.ORDER_NOT_FOUND);
        AssertUtil.equal(OrderState.WAIT_PAY, submitDto.getState(), OrderResultEnum.ORDER_HAS_PAID_OR_CANCEL);

        // 转换
        OrderSubmitVo orderSubmitVo = mapStructOrder.toOrderSubmitVo(submitDto);
        orderSubmitVo.setDeadline(submitDto.getCreateTime().plusSeconds(OrderRedisManager.getOrderCreateVoExpireTime()));

        return orderSubmitVo;
    }


    @Override
    public void deleteById(Long id) {

        Long memberId = StpUtil.getLoginIdAsLong();

        // 订单存在
        AssertUtil.isTrue(
                orderRepository.exist2Eq(
                        OrderDo::getId, id,
                        OrderDo::getMemberId, memberId,
                        OrderDo.class
                ),
                OrderResultEnum.ORDER_NOT_FOUND
        );

        // 仅已取消订单、已完成订单可以删除
        BinDto<BigInteger, Integer> dto = orderRepository.<BigInteger, Integer>selectBin1Eq(
                OrderDo::getParentId, OrderDo::getState,
                OrderDo::getId, id,
                OrderDo.class
        );
        OrderState state = orderRepository.selectOrderStateById(id, memberId);
        AssertUtil.notNull(state, OrderResultEnum.ORDER_NOT_FOUND);
        boolean f1 = ObjUtil.equal(dto.getV2(), OrderState.CANCEL.value()) || ObjUtil.equal(dto.getV2(), OrderState.END.value());
        AssertUtil.isTrue(f1, CommonResultEnum.OPERATION_NOT_SUPPORTED);

        // 事务包裹数据库操作
        transactionTemplate.executeWithoutResult(status -> {
            // 删除订单相关信息
            orderExtraRepository.delete1Eq(
                    OrderExtraDo::getOrderId, id,
                    OrderExtraDo.class
            );
            orderDetailRepository.delete2Eq(
                    OrderDetailDo::getOrderId, id,
                    OrderDetailDo::getMemberId, memberId,
                    OrderDetailDo.class
            );
            orderRepository.delete2Eq(
                    OrderDo::getId, id,
                    OrderDo::getMemberId, memberId,
                    OrderDo.class
            );
            // 检查父订单是否仍具有子订单
            boolean f2 = orderRepository.exist1Eq(
                    OrderDo::getParentId, dto.getV1(),
                    OrderDo.class
            );
            if (!f2) {
                orderRepository.delete1Eq(
                        OrderDo::getId, dto.getV1(),
                        OrderDo.class
                );
            }
        });


    }

    @Override
    public void deleteBatchByIdSet(Set<Long> idSet) {
        throw new CustomException(CommonResultEnum.OPERATION_NOT_SUPPORTED);
    }

    @Override
    public OrderAddressVo getAddressById(Long id) {

        // 订单地址
        LambdaQueryWrapper<OrderExtraDo> w = Wrappers.lambdaQuery(OrderExtraDo.class);
        w.select(
                OrderExtraDo::getCneeName, OrderExtraDo::getCneePhone, OrderExtraDo::getCneeAreaCode, OrderExtraDo::getCneeAddress
        ).eq(
                OrderExtraDo::getOrderId, id
        );
        OrderExtraDo order = orderExtraRepository.selectOne(w);
        AssertUtil.notNull(order, OrderResultEnum.ORDER_NOT_FOUND);

        // 转换
        OrderAddressVo oav = mapStructOrder.toOrderAddressVo(order);

        // 行政区域
        AreaFullLevelDto dto = areaApiService.getAreaFullLevelDtoList(Set.of(order.getCneeAreaCode())).get(0);
        oav.setCneeAreaCodeList(dto.getCodeList());


        return oav;
    }

    @Override
    public void updateAddress(OrderAddressUpdateQuery query) {

        SinDto<Integer> state = orderRepository.selectSin1Eq(
                OrderDo::getState,
                OrderDo::getId, query.getOrderId(),
                OrderDo.class
        );
        AssertUtil.notNull(state, OrderResultEnum.ORDER_NOT_FOUND);

        LambdaUpdateWrapper<OrderExtraDo> w = Wrappers.lambdaUpdate(OrderExtraDo.class);
        if (ObjUtil.equal(state.getV1(), OrderState.SPLIT.value())) {
            Set<Long> idSet = orderRepository.<BigInteger>selectSinList1Eq(
                    OrderDo::getId,
                    OrderDo::getParentId, query.getOrderId(),
                    OrderDo.class
            ).stream().map(it -> it.getV1().longValue()).collect(Collectors.toSet());
            idSet.add(query.getOrderId());
            w.in(OrderExtraDo::getOrderId, idSet);
        } else w.eq(OrderExtraDo::getOrderId, query.getOrderId());

        OrderExtraDo oed = mapStructOrder.toOrderExtraDo(query);
        orderExtraRepository.update(oed, w);
    }

    @Override
    public void confirmById(Long id) {
        SinDto<Integer> state = orderRepository.selectSin1Eq(
                OrderDo::getState,
                OrderDo::getId, id,
                OrderDo.class
        );
        AssertUtil.notNull(state, OrderResultEnum.ORDER_NOT_FOUND);
        AssertUtil.equal(
                state.getV1(),
                OrderState.WAIT_TAKE.value(),
                CommonResultEnum.OPERATION_NOT_SUPPORTED
        );
        orderRepository.update1Set1Eq(
                OrderDo::getState, OrderState.END,
                OrderDo::getId, id,
                OrderDo.class
        );
        orderExtraRepository.update1Set1Eq(
                OrderExtraDo::getSignedTime, LocalDateTime.now(),
                OrderExtraDo::getOrderId, id,
                OrderExtraDo.class
        );
    }

    @Override
    public List<WaitCommentVo> getWaitCommentList(Long id) {
        SinDto<Integer> state = orderRepository.selectSin1Eq(
                OrderDo::getState,
                OrderDo::getId, id,
                OrderDo.class
        );
        AssertUtil.notNull(state, OrderResultEnum.ORDER_NOT_FOUND);
        AssertUtil.equal(state.getV1(), OrderState.END.value(), CommonResultEnum.OPERATION_NOT_SUPPORTED);

        // key bookId; value orderDetailId
        Map<Long, Long> map = orderDetailRepository
                .<BigInteger, BigInteger>selectBinList2Eq(
                        OrderDetailDo::getBookId, OrderDetailDo::getId,
                        OrderDetailDo::getOrderId, id,
                        OrderDetailDo::getCommentId, 0L,
                        OrderDetailDo.class
                )
                .stream().collect(
                        Collectors.toMap(it -> it.getV1().longValue(), it -> it.getV2().longValue())
                );

        List<WaitCommentVo> voList = mapStructOrder.toWaitCommentVoList(
                bookApiService
                        .getBook4OrderCommentSuggestionDtoListByIdSet(
                                new HashSet<>(map.keySet())
                        )
        );
        voList.forEach(it -> it.setOrderDetailId(map.get(it.getBookId())));
        return voList;

    }


    /**
     * 构建分页查询Wrapper
     *
     * @param query 分页查询Wrapper
     * @return Wrapper
     */
    private LambdaQueryWrapper<OrderDo> buildPageQueryWrapper(OrderPageQuery query) {
        long memberId = StpUtil.getLoginIdAsLong();
        LambdaQueryWrapper<OrderDo> w = Wrappers.lambdaQuery(OrderDo.class);
        w.eq(OrderDo::getMemberId, memberId)
                .eq(query.getState() != null, OrderDo::getState, query.getState());
        if (ObjUtil.notBlank(query.getKeyword())) {
            LambdaQueryWrapper<OrderDetailDo> dw = Wrappers.lambdaQuery(OrderDetailDo.class);
            dw.like(OrderDetailDo::getTitle, query.getKeyword());
            Set<Long> oidSet = orderDetailRepository.selectList(dw).stream().map(OrderDetailDo::getOrderId).collect(Collectors.toSet());
            if (ObjUtil.isEmpty(oidSet)) {
                w.eq(OrderDo::getOrderNo, query.getKeyword());
            } else {
                w.and(it -> it.eq(OrderDo::getOrderNo, query.getKeyword()).or().in(OrderDo::getId, oidSet));
            }
        }
        return w;
    }

}
